#pragma once
#ifndef OBR_MIPMAPDS_H
#define OBR_MIPMAPDS_H

#include "DScommon.h"
#include "TextureDS.h"

namespace OBR
{
enum class MipmapSampleMode
{
    SQUARE,
    ELIPSE,
    DISABLE
};

template <typename DataType> struct DeviceMipmap
{
    uint num_levels;
    float minstep;
    DeviceTexture2D<DataType> *levels; // level 0 <==> LOD 0 is the most detailed one

    __forceinline__ __device__ DataType sample(float2 uv, float du = 0, float dv = 0,
                                               MipmapSampleMode mode = MipmapSampleMode::SQUARE)
    {
        if (mode == MipmapSampleMode::DISABLE || (du == 0 && dv == 0))
        {
            return levels[0].sample(uv, TextureSampleMode::CLOSEST);
        }
        else if (mode == MipmapSampleMode::SQUARE)
        {
            float radius = (du + dv) * 0.5f;
            float level = num_levels - clamp(-log2f(radius), 0.0f, (float)(num_levels - 1));
            uint l0 = clamp(floorf(level), 0.0f, (float)(num_levels - 1));
            DataType v0 = levels[l0].sample(uv, TextureSampleMode::XLINEAR);
            if (l0 < num_levels - 1)
            {
                DataType v1 = levels[l0 + 1].sample(uv, TextureSampleMode::XLINEAR);
                return interp_1D<DataType>(v0, v1, level - l0);
            }
            else
            {
                return v0;
            }
        }
        return levels[0].at(0, 0);
    }
};

} // namespace OBR

#endif
